﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using DDD;
using FloatComparer = UnitTest.TestHelper.FloatComparer;

namespace UnitTest {
    [TestClass]
    public class TestUniform_bool_bvec2_bvec3_bvec4_ {

        #region Field
        GameWindow window;
        World wld;
        Graphics3D g3d;
        FrameBuffer fbuf;
        #endregion

        #region Setup
        [TestInitialize ()]
        public void MyClassInitialize () {
            window = new GameWindow ();
            wld = CreateWorld ();
            fbuf = CreateFrameBuffer ();

            g3d = Graphics3D.GetInstance ();
            g3d.Reset ();

            g3d.RenderPass += delegate {
                g3d.SetFrameBuffer (fbuf);
                g3d.SetWorld (wld);
                g3d.SetViewort (0, 0, 1, 1);
            };
        }

        [TestCleanup ()]
        public void MyClassCleanup () {
            window.Dispose ();
            window = null;
            wld = null;
        }

        private static FrameBuffer CreateFrameBuffer () {
            var fbuf = new FrameBuffer (8, 1, 0);
            var color0 = new Image2D<byte> (DDD.PixelFormat.R8ui, 1, 1);
            var color1 = new Image2D<byte> (DDD.PixelFormat.RG8ui, 1, 1);
            var color2 = new Image2D<byte> (DDD.PixelFormat.RGB8ui, 1, 1);
            var color3 = new Image2D<byte> (DDD.PixelFormat.R8ui, 1, 1);
            var color4 = new Image2D<byte> (DDD.PixelFormat.RG8ui, 1, 1);
            var color5 = new Image2D<byte> (DDD.PixelFormat.RGB8ui, 1, 1);
            var color6 = new Image2D<byte> (DDD.PixelFormat.RGBA8ui, 1, 1);
            var color7 = new Image2D<byte> (DDD.PixelFormat.RGBA8ui, 1, 1);
            fbuf.SetColorBuffer (0, color0);
            fbuf.SetColorBuffer (1, color1);
            fbuf.SetColorBuffer (2, color2);
            fbuf.SetColorBuffer (3, color3);
            fbuf.SetColorBuffer (4, color4);
            fbuf.SetColorBuffer (5, color5);
            fbuf.SetColorBuffer (6, color6);
            fbuf.SetColorBuffer (7, color7);
            return fbuf;
        }

        private World CreateWorld () {
            var cam = new Camera ();
            cam.SetPerspective (45, 1, 0.1f, 10f);

            var camNode = new Node ();
            camNode.Attach (cam);
            camNode.SetTranslation (0, 0, 1);

            var pos = new float[3] { 0, 0, 0 };
            var posArray = new VertexArray<float> (1, 3);
            posArray.Set (0, 1, pos);

            var vbuf = new VertexBuffer ();
            vbuf.AddVertexArray ("v_Position", posArray);

            var ibuf = new IndexBuffer<int> (PrimitiveType.Point, 1);
            var indices = new int[] { 0 };
            ibuf.Set (0, 1, indices);

            var vert = @"#version 400
                         in  vec3 v_Position;
                               
                         void main () {
                             gl_Position = vec4(v_Position, 1);
                         }
                        ";
            var frag = @"#version 400
                         uniform bool   Color0;
                         uniform bvec2  Color1;
                         uniform bvec3  Color2;
                         uniform bool   Color3;
                         uniform bool   Color4[2];
                         uniform bvec3  Color5;

                         out int    frag_Color0;
                         out ivec2  frag_Color1;
                         out ivec3  frag_Color2;
                         out int    frag_Color3;
                         out ivec2  frag_Color4;
                         out ivec3  frag_Color5;

                         void main () {
                             if (Color0 == true) 
                                frag_Color0 = 1;
                             else
                                frag_Color0 = 2;

                             if (Color1.x == true)
                                frag_Color1.x = 1;
                             else
                                frag_Color1.x = 2; 
                             if (Color1.y == true)
                                frag_Color1.y = 1;
                             else
                                frag_Color1.y = 2;
                                 
                             if (Color2.x == true)
                                frag_Color2.x = 1;
                             else
                                frag_Color2.x = 2; 
                             if (Color2.y == true)
                                frag_Color2.y = 1;
                             else
                                frag_Color2.y = 2;
                             if (Color2.z == true)
                                frag_Color2.z = 1;
                             else
                                frag_Color2.z = 2;
                             

                             if (Color3 == true)
                                frag_Color3 = 1;
                             else
                                frag_Color3 = 2;

                             if (Color4[0] == true)
                                frag_Color4.x = 1;
                             else
                                frag_Color4.x = 2;
                             if (Color4[1] == true)
                                frag_Color4.y = 1;
                             else
                                frag_Color4.y = 2;

                             if (Color5.x == true)
                                frag_Color5.x = 1;
                             else
                                frag_Color5.x = 2;
                             if (Color5.y == true)
                                frag_Color5.y = 1;
                             else
                                frag_Color5.y = 2;
                             if (Color5.z == true)
                                frag_Color5.z = 1;
                             else
                                frag_Color5.z = 2;
                        }
                        ";

            var vs = new VertexShader (new MemoryStream (Encoding.UTF8.GetBytes (vert)));
            var fs = new FragmentShader (new MemoryStream (Encoding.UTF8.GetBytes (frag)));
            var sp = new ShaderProgram (vs, fs);

            var mat = new TestMaterial ();
            mat.R2 = true;
            mat.Array2 = new bool[2] { true, false };
            mat.RGB2 = new Vector3<bool> (true, false, false);
      
            var unifs = new UniformArray ();
            unifs.Add ("Color0", true);                                               // 即値
            unifs.Add ("Color1", new bool[2] { true, false });                            // 即値(配列)
            unifs.Add ("Color2", new Vector3<bool> (true, false, false));                     // 即値(構造体)
            unifs.Add ("Color3", mat, () => mat.R2);                             // プロパティ
            unifs.Add ("Color4[0]", mat, () => mat.Array2);                      // プロパティ(配列)
            unifs.Add ("Color5", UniformArray.CurrentMaterial, () => mat.RGB2);  // プロパティ(実行時バインド,構造体)

            var app = new Appearance ();
            app.SetShaderProgram (sp);
            app.AddUniformArray (unifs);
            app.SetMaterial (mat);

            var msh = new Mesh ();
            msh.SetVertexBuffer (vbuf);
            msh.SetIndexBuffer (ibuf);
            msh.SetAppearance (app);

            var mshNode = new Node ();
            mshNode.Attach (msh);

            var wld = new World ();
            wld.AddChild (camNode);
            wld.AddChild (mshNode);
            wld.SetActiveCamera (camNode);

            return wld;
        }

        #endregion



        #region TestMethod
        [TestMethod]
        public void TestMethod1 () {

            g3d.Render ();
            window.SwapBuffers ();

            var expected0 = new byte[1] { 1 };
            var expected1 = new byte[2] { 1, 2 };
            var expected2 = new byte[3] { 1, 2, 2 };
            var expected3 = new byte[1] { 1 };
            var expected4 = new byte[2] { 1, 2 };
            var expected5 = new byte[3] { 1, 2, 2 };
            var pixels0 = new byte[1];
            var pixels1 = new byte[2];
            var pixels2 = new byte[3];
            var pixels3 = new byte[1];
            var pixels4 = new byte[2];
            var pixels5 = new byte[3];
            var color0 = fbuf.GetColorBuffer (0) as Image2D<byte>;
            var color1 = fbuf.GetColorBuffer (1) as Image2D<byte>;
            var color2 = fbuf.GetColorBuffer (2) as Image2D<byte>;
            var color3 = fbuf.GetColorBuffer (3) as Image2D<byte>;
            var color4 = fbuf.GetColorBuffer (4) as Image2D<byte>;
            var color5 = fbuf.GetColorBuffer (5) as Image2D<byte>;
            color0.Capture ();
            color1.Capture ();
            color2.Capture ();
            color3.Capture ();
            color4.Capture ();
            color5.Capture ();
            color0.Get (0, 0, 1, 1, pixels0);
            color1.Get (0, 0, 1, 1, pixels1);
            color2.Get (0, 0, 1, 1, pixels2);
            color3.Get (0, 0, 1, 1, pixels3);
            color4.Get (0, 0, 1, 1, pixels4);
            color5.Get (0, 0, 1, 1, pixels5);

            CollectionAssert.AreEqual (expected0, pixels0);
            CollectionAssert.AreEqual (expected1, pixels1);
            CollectionAssert.AreEqual (expected2, pixels2);
            CollectionAssert.AreEqual (expected3, pixels3);
            CollectionAssert.AreEqual (expected4, pixels4);
            CollectionAssert.AreEqual (expected5, pixels5);
        }
        #endregion



    }
}
